/**
 * @file   element1d.h
 * @author ubuntu <dadi@ubuntu>
 * @date   Sun Mar 28 23:25:38 2021
 * 
 * @brief   
 * 
 * 
 */

#ifndef __DADI_ELEMENT__
#define __DADI_ELEMENT__

#include<iostream>
#include<fstream>

template <int DIM, class T>
class Point_1
{
  private:
    T *coord;
    int index;
  public:
    /** 
     * Default constructor.
     * 
     */
    Point_1();

    /** 
     * Constructor. Create a point with given coord.
     * 
     * @param _x Given coord.
     */
    Point_1(double _x);

    /** 
     * Constructor. Create a point with given coord and given index.
     * 
     * @param _x Given coord.
     * @param _i Given index.
     */
    Point_1(double _x, int _i);

    /** 
     * Destructor.
     * 
     */
    ~Point_1();

    /** 
     * Constructor. Create a point with given address of another point.
     * 
     * @param _p Given address of another point.
     */
    Point_1(const Point_1 &_p);

    /** 
     * Get the index of the point.
     * 
     * 
     * @return The index of the point.
     */
    int get_index() const;

    /** 
     * Set point for the point.
     * 
     * @param _i The index to be set.
     */
    void set_index(int _i);

    /** 
     * Get the coord of the point.
     * 
     * 
     * @return The coord of the point.
     */
    double get_coord() const;

    /** 
     * Set point for the point.
     * 
     * @param _c The coord to be set.
     */
    void set_coord(double _c);

    /** 
     * Overload the equal sign.
     * 
     * @param _p Given point. 
     * 
     * @return New point.
     */
    const Point_1& operator=(const Point_1 &_p);
    
    friend std::ostream& operator<<(std::ostream &_os, const Point_1 &_p);
    
    friend Point_1 operator+(const Point_1 &_p1, const Point_1 &_p2);
};

std::ostream& operator<<(std::ostream &_os, const Point_1 &_p);

Point_1 operator+(const Point_1 &_p1, const Point_1 &_p2);

class Interval
{
  private:
    Point_1 a;
    Point_1 b;
  public:
    /** 
     * Default constructor.
     * 
     */
    Interval();

    /** 
     * Constructor.
     * 
     * @param _a The coord of the left end point of the interval.
     * @param _b The coord of the right end point of the interval.
     */
    Interval(double _a, double _b);

    /** 
     * Constructor.
     * 
     * @param _a The left end point of the interval.
     * @param _b The right end point of the interval.
     */
    Interval(const Point_1 &_a, const Point_1 &_b);

    /** 
     * Destructor.
     * 
     */
    ~Interval();

    /** 
     * Set the left end point of the interval.
     * 
     * @param _a Given point. 
     */
    void set_a(const Point_1 &_a);

    /** 
     * Set the right end point of the interval.
     * 
     * @param _b Given point.
     */
    void set_b(const Point_1 &_b);

    /** 
     * Get the left end point of the interval.
     * 
     * 
     * @return The address of the left end point of the interval.
     */
    const Point_1& get_a() const;

    /** 
     * Get the right end point of the interval.
     * 
     * 
     * @return The address of the right end point of the interval.
     */
    const Point_1& get_b() const;
    
    friend std::ostream& operator<<(std::ostream &_os, const Interval &_i);
};

std::ostream& operator<<(std::ostream &_os, const Interval &_i);

class Mesh_1
{
  private:
    int n_elements;
    Interval *elements; 
    //Change the nodes to elements. The function Mesh1 can get all elements.
    //The function get_element can call directly each element by addressing.
    Interval *area;
  public:
    /** 
     * Get the element in the area.
     * 
     * @param _i The index of the element.
     * 
     * @return The element.
     */
    const Interval& get_element(int _i);

    /** 
     * Default constructor.
     * 
     */
    Mesh_1();

    /** 
     * Destructor.
     * 
     */
    ~Mesh_1();

    /** 
     * Constructor.
     * 
     * @param _a All points.
     * @param _n_nodes The number of the points.
     */
    Mesh_1(const Point_1 *_a, int _n_nodes);

    /** 
     * Get the number of the elements.
     * 
     * 
     * @return The number of the elements.
     */
    int get_n_elements() const;

    /** 
     * Get the number of the nodes.
     * 
     * 
     * @return The number of the nodes.
     */
    int get_n_nodes() const;   
};

/* class Element_1 */
/* { */
/*   private: */
/*     Point_1 a; */
/*     Point_1 b; */
/*   public: */
/*     /\** */
/*      * Default constructor. */
/*      * */
/*      *\/ */
/*     Element_1(); */

/*     /\** */
/*      * Constructor. */
/*      * */
/*      * @param _a */
/*      * @param _b */
/*      *\/ */
/*     Element_1(const Point_1& _a, const Point_1& _b); */

/*     /\** */
/*      * Destructor. */
/*      * */
/*      *\/ */
/*     ~Element_1(); */

/*     /\** */
/*      * Set the left end point of the element. */
/*      * */
/*      * @param _a Given point. */
/*      *\/ */
/*     void set_a(const Point_1& _a); */

/*     /\** */
/*      * Set the right end point of the element. */
/*      * */
/*      * @param _a Given point. */
/*      *\/ */
/*     void set_b(const Point_1& _b); */

/*     /\** */
/*      * B-spline. */
/*      * */
/*      * @param _x */
/*      * */
/*      * @return */
/*      *\/ */
/*     double phi_a(double _x); */

/*     /\** */
/*      * B-spline. */
/*      * */
/*      * @param _x */
/*      * */
/*      * @return */
/*      *\/ */
/*     double phi_b(double _x); */
/* }; */

class Quad_Info
{
  private:
    int accuracy;
    int n_q_points;
    double **q_info;
  public:
    /** 
     * Default constructor.
     * 
     */
    Quad_Info();

    /** 
     * Set Quad_Info.
     * 
     * @param _acc accuracy.
     * @param _n_q_pnts The number of Quad points.
     * @param _q_info The value and the weight.
     */
    void set(int _acc, int _n_q_pnts, double **_q_info);

    /** 
     * Get accuracy.
     * 
     * 
     * @return Accuracy.
     */
    int get_accuracy() const;

    /** 
     * Get the number of the Quad points.
     * 
     * 
     * @return The number of the Quad points.
     */
    int get_n_q_points() const;

    /** 
     * Get the value and the weight.
     * 
     * @param _idx The index.
     * 
     * @return The value and the weight.
     */
    const double* get_pAw(int _idx) const;

    /** 
     * Destructor.
     * 
     */
    ~Quad_Info();
};

class Quad
{
  private:
    int n_table;
    Quad_Info *quad_info;
  public:
    /** 
     * Default constructor.
     * 
     */
    Quad();

    /** 
     * Destructor.
     * 
     */
    ~Quad();

    /** 
     * Load the Quad table.
     * 
     * @param _file Given by user.
     */
    void load_data(const char _file[]);

    /** 
     * Get the number of tables.
     * 
     * 
     * @return The number of tables. 
     */
    int get_n_table() const;

    /** 
     * Given the table whose accuracy satisfies the user.s
     * 
     * @param _acc 
     * 
     * @return 
     */
    const Quad_Info& get_quad_info(int _acc) const;

    void list() const;

    /** 
     * Global to local.
     * 
     * @param _a 
     * @param _b 
     * @param _x 
     * 
     * @return 
     */
    double g2l(double _a, double _b, double _x) const;

    /** 
     * Local to global.
     * 
     * @param _a 
     * @param _b 
     * @param _t 
     * 
     * @return 
     */
    double l2g(double _a, double _b, double _t) const;
    
    double Jacobian(double _a, double _b) const;
};


#else
//Do nothing
#endif
